//
//  StaticTimeScheduler.m
//  location
//
//  Created by Assistant on 2025/10/15.
//

#import "StaticTimeScheduler.h"

@interface StaticTimeScheduler ()

@property (nonatomic, strong) dispatch_queue_t serialQ;               // 串行执行队列
@property (nonatomic, strong) NSMutableDictionary<NSString *, NSDictionary *> *pendingByUserId; // userId -> latest location

@end

@implementation StaticTimeScheduler

+ (instancetype)shared
{
    static StaticTimeScheduler *ins = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        ins = [[StaticTimeScheduler alloc] initPrivate];
    });
    return ins;
}

- (instancetype)initPrivate
{
    if (self = [super init]) {
        _serialQ = dispatch_queue_create("com.location.staticTime.serial", DISPATCH_QUEUE_SERIAL);
        _pendingByUserId = [NSMutableDictionary dictionary];
    }
    return self;
}

- (instancetype)init
{
    [NSException raise:@"Use shared" format:@"Use +[StaticTimeScheduler shared] instead."];
    return nil;
}

- (void)enqueueWithUserId:(NSString *)userId
                 location:(NSDictionary *)location
                   worker:(void (^)(NSString * _Nonnull, NSDictionary * _Nullable, void (^ _Nonnull)(NSString * _Nullable)))worker
                    apply:(void (^)(NSString * _Nullable))apply
{
    if (userId.integerValue == 0 || worker == nil) { return; }

    // 合并：同一 userId 始终保留最新参数
    @synchronized (self) {
        self.pendingByUserId[userId] = location ?: @{};
    }

    // 串行队列逐个取出并执行
    __weak typeof(self) weakSelf = self;
    dispatch_async(self.serialQ, ^{
        __strong typeof(weakSelf) selfRef = weakSelf; if (!selfRef) return;

        // 取出并清除该 userId 的最新任务（去抖，last-write-wins）
        NSDictionary *args = nil;
        @synchronized (selfRef) {
            args = selfRef.pendingByUserId[userId];
            [selfRef.pendingByUserId removeObjectForKey:userId];
        }
        if (!args) { return; }

        // 使用信号量等待异步 complete，确保严格逐个执行
        dispatch_semaphore_t sema = dispatch_semaphore_create(0);

        // 执行后台工作；worker 内部完成后调用 complete，结果再派发到主线程执行 apply
        worker(userId, args, ^(NSString * _Nullable startTime) {
            if (apply) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    apply(startTime);
                });
            }
            dispatch_semaphore_signal(sema);
        });

        // 等待任务完成（或在 worker 内部调用 complete）
        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    });
}

- (void)cancelPendingForUserId:(NSString *)userId
{
    if (userId.length == 0) return;
    @synchronized (self) {
        [self.pendingByUserId removeObjectForKey:userId];
    }
}

- (void)cancelAllPending
{
    @synchronized (self) {
        [self.pendingByUserId removeAllObjects];
    }
}

@end


